home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 5791 / 5791.xpi / chrome / flagfox.jar / content / flagfox.js < prev    next >
Text File  |  2009-02-04  |  22KB  |  550 lines

  1. var FFpreferences = null;
  2.  
  3. var warningsThisSession = [];
  4.  
  5. var flagfoxstrings = null; // localized strings
  6. var countrynames = null;   // localized country names
  7.  
  8. var FlagfoxPollLoopID;
  9.  
  10. function Flagfox_startup()
  11. {
  12.     try
  13.     {
  14.         window.removeEventListener("load", Flagfox_startup, false);
  15.  
  16.         if (!document.getElementById("main-window"))
  17.         {
  18.             Components.utils.reportError("Flagfox warning: attempted to load into an invalid window");
  19.             return;
  20.         }
  21.  
  22.         flagState.icon = document.getElementById("flagfox-icon");
  23.         if (!flagState.icon)
  24.             throw "Could not find icon";
  25.  
  26.         countrynames = document.getElementById("flagfox-countrynames");
  27.         if (!countrynames || !countrynames.strings.hasMoreElements())
  28.             throw "Could not load country names";
  29.  
  30.         flagfoxstrings = document.getElementById("flagfox-localizedstrings");
  31.         if (!flagfoxstrings || !flagfoxstrings.strings.hasMoreElements())
  32.             throw "Could not load localized strings";
  33.  
  34.         FFpreferences = Components.classes["@mozilla.org/preferences-service;1"]
  35.                                   .getService(Components.interfaces.nsIPrefBranch);
  36.         if (!FFpreferences)
  37.             throw "Could not fetch preferences service";
  38.  
  39.         if (FlagfoxPollLoopID !== undefined)
  40.             throw "Flagfox is already loaded!";
  41.  
  42.         window.addEventListener("unload", Flagfox_shutdown, false);
  43.  
  44.         Flagfox_cleanupPrefs();           // Clear any pref entries from old versions
  45.         Flagfox_setIconPos();             // Place flag icon based on pref
  46.         Flagfox_prefObserver.register();  // Listen for preferences changes
  47.         Flagfox_dnsHandler.init();        // Fetch the services we need for DNS
  48.         Flagfox_loadIPDB();               // Load IPDB from "profileDir/extensionDir/db.dat"
  49.  
  50.         // Check if add-on updates are enabled globally, or at least for Flagfox
  51.         if (!Flagfox_safeGetBoolPref("extensions.update.enabled") &&
  52.             !Flagfox_safeGetBoolPref("extensions.{1018e4d6-728f-4b20-ad56-37578a4de76b}.update.enabled"))
  53.         {
  54.             Flagfox_warning("flagfox.warn.updates", flagfoxstrings.getString("updateswarnmessage"));
  55.         }
  56.     }
  57.     catch (e)
  58.     {
  59.         if (e == "_setIconPos-abortStartup_")
  60.             return;  // Failed to place icon; already shut down and don't need to show message
  61.  
  62.         if (flagState.icon)
  63.         {
  64.             flagState.icon.src = "chrome://flagfox/content/icons/special/error.png";
  65.             flagState.icon.tooltipText = "Flagfox failed to load!";
  66.         }
  67.  
  68.         Flagfox_shutdown();
  69.         Flagfox_error("Flagfox failed to load!",e);
  70.         return;
  71.     }
  72.  
  73.     // Start polling loop
  74.     FlagfoxPollLoopID = setInterval(Flagfox_pollWindowURL, 250);
  75. }
  76.  
  77. function Flagfox_shutdown()
  78. {
  79.     window.removeEventListener("unload", Flagfox_shutdown, false);
  80.  
  81.     clearInterval(FlagfoxPollLoopID);
  82.     Flagfox_dnsHandler.reset();
  83.     Flagfox_prefObserver.unregister();
  84.     Flagfox_closeIPDB();
  85. }
  86.  
  87. var flagState =
  88. {
  89.     url : "init",
  90.     host : "",
  91.     ip : "",
  92.     country : null,
  93.     icon : null,
  94.  
  95.     newURL : function(newurl)
  96.     {
  97.         this.url = newurl;
  98.         this.host = "";
  99.         this.ip = "";
  100.         this.country = null;
  101.     },
  102.  
  103.     IPisV6 : function()
  104.     {
  105.         return this.ip.indexOf(':') != -1;  // a:b:c:d:e:f:g:h for IPv6 vs. a.b.c.d for IPv4
  106.     },
  107.  
  108.     serverString : function()
  109.     {
  110.         if (this.host == this.ip)
  111.             return this.ip;
  112.         switch (textdirection)  // via global.dtd
  113.         {
  114.             default:
  115.             case "ltr": return this.host + " (" + this.ip + ")";
  116.             /* I'm forced to work around Mozilla's automatic RTL punctuation flipping bugs here.
  117.                "host (ip)" shows as "(host (ip". The following should show as "host (ip)" for all instances.
  118.                There is no way to consistently show "(ip) host" in RTL, as it tries to flip the word order. */
  119.             case "rtl": return "(" + this.host + " (" + this.ip;
  120.         }
  121.     },
  122.  
  123.     tooltipString : function()
  124.     {
  125.         return flagfoxstrings.getFormattedString( "tooltip", [this.serverString(),this.country[1]] );
  126.     }
  127. };
  128.  
  129. var Flagfox_prefObserver =
  130. {
  131.     branch : null,  // the pref branch we're observing
  132.  
  133.     register : function()
  134.     {
  135.         this.branch = Components.classes["@mozilla.org/preferences-service;1"]
  136.                                 .getService(Components.interfaces.nsIPrefService)
  137.                                 .getBranch("flagfox.");
  138.         this.branch.QueryInterface(Components.interfaces.nsIPrefBranch2);
  139.         this.branch.addObserver("", this, false);
  140.     },
  141.  
  142.     unregister : function()
  143.     {
  144.         if (this.branch != null)
  145.             this.branch.removeObserver("", this);
  146.     },
  147.  
  148.     observe : function(aSubject, aTopic, aData)
  149.     {
  150.         if (aTopic != "nsPref:changed")
  151.             return;
  152.         switch (aData)
  153.         {
  154.             case "usealticons":
  155.                 Flagfox_setIconSrc();
  156.                 break;
  157.             case "position.bar":
  158.             case "position.side":
  159.                 Flagfox_setIconPos();
  160.                 break;
  161.             case "warn.tld":
  162.             case "warn.proxy":
  163.                 if (this.branch.getBoolPref(aData)==true)
  164.                     warningsThisSession = [];  // Reset list on pref reset
  165.                 break;
  166.         }
  167.     }
  168. };
  169.  
  170. function Flagfox_setIconPos()
  171. {
  172.     try
  173.     {
  174.         function safeGetElementById(id)
  175.         {
  176.             var element = document.getElementById(id);
  177.             if (!element)
  178.                 throw "Element does not exist: " + id;
  179.             return element;
  180.         }
  181.         function deleteElementById(id)
  182.         {
  183.             var node = document.getElementById(id);
  184.             if (!node)
  185.                 return;
  186.             node.parentNode.removeChild(node);
  187.             if (document.getElementById(id) != null)
  188.                 throw "Failed to delete element: " + id;
  189.         }
  190.         function wrapElementWith(node,type,id)
  191.         {
  192.             var wrapper = document.createElement(type);
  193.             wrapper.setAttribute("id",id);
  194.             wrapper.appendChild(node);
  195.             return wrapper;
  196.         }
  197.  
  198.         /* Rather than detecting where the icon is and move it from there to its new location,
  199.            I move it into a temporary location and then delete both possible previous wrappers.
  200.            As a result, I can simply place the icon in the same generic way every time. */
  201.         var iconBox = safeGetElementById("flagfox-iconbox");
  202.         iconBox.hidden = true;
  203.         safeGetElementById("main-window").appendChild(iconBox);
  204.         if (!iconBox)
  205.             throw "Lost flagfox-iconbox in main-window";
  206.  
  207.         // Cleanup any existing panels
  208.         deleteElementById("flagfox-statusbarpanel");
  209.         deleteElementById("flagfox-addressbarpanel");
  210.  
  211.         var bar, panel, nextSibling;
  212.         var iconLoc = FFpreferences.getCharPref("flagfox.position.bar");   // What bar is it in?
  213.         var iconPos = FFpreferences.getCharPref("flagfox.position.side");  // Where in that bar is it?
  214.         switch (iconLoc)
  215.         {
  216.             case "statusbar":  // Positions reversed in right-to-left locales
  217.                 bar = safeGetElementById("status-bar");
  218.                 panel = wrapElementWith(iconBox,"statusbarpanel","flagfox-statusbarpanel");
  219.                 if (textdirection == "rtl")  // via global.dtd
  220.                 {
  221.                     var flip = [];  // Need to flip positioning to match strings
  222.                     flip["LM"]="RM"; flip["L"]="R"; flip["R"]="L"; flip["RM"]="LM";
  223.                     iconPos = flip[iconPos];
  224.                 }
  225.                 switch (iconPos)
  226.                 {
  227.                     case "LM":
  228.                         nextSibling = bar.firstChild;
  229.                         break;
  230.                     case "L":
  231.                         nextSibling = document.getElementById("statusbar-display");
  232.                         if (!nextSibling)
  233.                             nextSibling = bar.firstChild;
  234.                         break;
  235.                     case "R":
  236.                         var popBlockBtn = document.getElementById("page-report-button");
  237.                         if (!popBlockBtn)
  238.                             popBlockBtn = document.getElementById("popupIcon");  // SeaMonkey 2 support (button has different ID)
  239.                         nextSibling = popBlockBtn ? popBlockBtn.nextSibling : null ;
  240.                         break;
  241.                     case "RM":
  242.                         nextSibling = null;
  243.                         break;
  244.                 }
  245.                 break;
  246.  
  247.             case "addressbar":  // Positions _NOT_ reversed in right-to-left locales
  248.                 bar = safeGetElementById("urlbar-icons");
  249.                 panel = wrapElementWith(iconBox,"box","flagfox-addressbarpanel");
  250.                 switch (iconPos)
  251.                 {
  252.                     case "LM": case "L":       // REQUIRES FF3+
  253.                         nextSibling = bar;     // Will place icon to left of address field
  254.                         bar = bar.parentNode;  // Jump out of normal icon box
  255.                         panel.style.marginLeft = "4px";
  256.                         break;
  257.                     case "R":
  258.                         nextSibling = document.getElementById("star-button");  // If not FF3+ this'll be null => "RM"
  259.                         if (nextSibling && nextSibling.parentNode.id != bar.id)
  260.                             nextSibling = null;  // Flock 2 support ("star-button" is not in "urlbar-icons")
  261.                         break;
  262.                     case "RM":
  263.                         nextSibling = null;
  264.                         break;
  265.                  }
  266.                 break;
  267.         }
  268.         if (nextSibling === undefined)
  269.             throw "Invalid position: " + iconLoc + "-" + iconPos;
  270.  
  271.         // Make the placement
  272.         bar.insertBefore(panel,nextSibling);
  273.         iconBox.hidden = false;
  274.     }
  275.     catch (e)
  276.     {
  277.         Flagfox_shutdown();  // This window probably just lacks an address bar or status bar; Flagfox can't work in this window
  278.         if (String(e).substr(0,22) == "Element does not exist")
  279.             Components.utils.reportError("Flagfox warning: attempted to load icon into an unsupported window; \n" + e);
  280.         else
  281.             Flagfox_error("Error setting icon position",e);
  282.         throw "_setIconPos-abortStartup_";  // Abort startup sequence, if needed
  283.     }
  284. }
  285.  
  286. function Flagfox_setIconSrc()  // Applies to looked-up IPs only; others are done in the protocol switch
  287. {
  288.     if (flagState.country == null)
  289.         return;  // Flag is for local file or unknown site
  290.  
  291.     var file;
  292.     switch (flagState.country[0])
  293.     {
  294.         case '-A':  case '-B':  case '-C':
  295.             file = "special/privateip";
  296.             break;
  297.         case '-L':
  298.             file = "special/localhost";
  299.             break;
  300.         case 'A1':  case 'A2':
  301.             file = "special/anonymous";
  302.             break;
  303.         default:
  304.             var set = FFpreferences.getBoolPref("flagfox.usealticons") ? "flagset2/" : "flagset1/";
  305.             file = set + flagState.country[0].toLowerCase();
  306.             break;
  307.     }
  308.     flagState.icon.src = "chrome://flagfox/content/icons/" + file + ".png";
  309. }
  310.  
  311. function Flagfox_pollWindowURL()
  312. {
  313.     try
  314.     {
  315.         if (flagState.url != window.content.document.location.href)
  316.         {
  317.             flagState.newURL(window.content.document.location.href);
  318.             Flagfox_dnsHandler.reset();  // If we've changed pages before completing a lookup, then abort the old request and use this new one
  319.  
  320.             switch (window.content.document.location.protocol)
  321.             {
  322.                 case "file:":
  323.                     flagState.icon.src = "chrome://flagfox/content/icons/special/localfile.png";
  324.                     flagState.icon.tooltipText = flagfoxstrings.getString("localfile");
  325.                     return;  // Done
  326.  
  327.                 case "about:":  case "chrome:":  case "resource:":  case "data:":
  328.                     if (window.content.document.URL == "about:blank")
  329.                     {   // Blank page gets its own icon and tooltip
  330.                         flagState.icon.src = "chrome://flagfox/content/icons/special/blank.png";
  331.                         flagState.icon.tooltipText = flagfoxstrings.getString("blankpage");
  332.                     }
  333.                     else
  334.                     {
  335.                         flagState.icon.src = "chrome://flagfox/content/icons/special/resource.png";
  336.                         flagState.icon.tooltipText = flagfoxstrings.getString("localfile") + " (" + window.content.document.location.protocol + "//)";
  337.                     }
  338.                     return;  // Done
  339.  
  340.                 default:
  341.                     flagState.icon.src = "chrome://flagfox/content/icons/special/unknown.png";
  342.                     flagState.icon.tooltipText = flagfoxstrings.getString("unknownsite");
  343.                     break;  // Consider unknown until we can look it up
  344.             }
  345.  
  346.             flagState.host = window.content.document.location.hostname;
  347.             flagState.host = flagState.host.cropTrailingChar(".");  // Get rid of root dot, if it's there
  348.             if (flagState.host == "")
  349.             {
  350.                 Components.utils.reportError("Flagfox warning: no host");  // Not necessarily an error; show in error console if enabled
  351.                 return;
  352.             }
  353.  
  354.             if (Flagfox_dnsHandler.detectDNSProxy())
  355.             {
  356.                 flagState.icon.src = "chrome://flagfox/content/icons/special/anonymous.png";
  357.                 flagState.icon.tooltipText = flagfoxstrings.getString("proxywarntitle");
  358.                 Components.utils.reportError("Flagfox warning: disabled due to proxy");
  359.  
  360.                 Flagfox_warning("flagfox.warn.proxy", flagfoxstrings.getString("proxywarnmessage"));
  361.                 return;  // Proxy in use for DNS; can't do a DNS lookup
  362.             }
  363.  
  364.             // Idealy just hitting the DNS cache here
  365.             Flagfox_dnsHandler.resolveHost();
  366.             // Calls back to Flagfox_dnsHandler.onLookupComplete()
  367.         }
  368.     }
  369.     catch (e) { Components.utils.reportError("Flagfox EXCEPTION: " + Flagfox_parseException(e)); }
  370. }
  371.  
  372. var Flagfox_dnsHandler =
  373. {
  374.     dns : null,      // DNS service
  375.     ios : null,      // I/O service
  376.     proxy : null,    // proxy service
  377.     thread : null,   // this thread; onLookupComplete() must be called in this thread
  378.     request : null,  // current DNS request in progress; cancel with this.reset()
  379.  
  380.     init : function()
  381.     {
  382.         this.dns = Components.classes["@mozilla.org/network/dns-service;1"]
  383.                              .getService(Components.interfaces.nsIDNSService);
  384.         this.ios = Components.classes["@mozilla.org/network/io-service;1"]
  385.                              .getService(Components.interfaces.nsIIOService);
  386.         this.proxy = Components.classes["@mozilla.org/network/protocol-proxy-service;1"]
  387.                                .getService(Components.interfaces.nsIProtocolProxyService);
  388.  
  389.         var EQS = Components.classes["@mozilla.org/event-queue-service;1"];
  390.         if (EQS)  // Firefox 1.5 - 2.0
  391.         {
  392.             EQS = EQS.getService(Components.interfaces.nsIEventQueueService);
  393.             this.thread = EQS.getSpecialEventQueue(EQS.CURRENT_THREAD_EVENT_QUEUE);
  394.         }
  395.         else      // Firefox 3.0+
  396.         {
  397.             this.thread = Components.classes["@mozilla.org/thread-manager;1"]
  398.                                     .getService(Components.interfaces.nsIThreadManager)
  399.                                     .currentThread;
  400.         }
  401.         if (!this.thread)
  402.             throw "Could not fetch current thread for DNS handler";
  403.     },
  404.  
  405.     reset : function()
  406.     {
  407.         if (this.request != null)
  408.         {
  409.             this.request.cancel(Components.results.NS_ERROR_ABORT);  // calls onLookupComplete() with status=Components.results.NS_ERROR_ABORT
  410.             this.request = null;
  411.         }
  412.     },
  413.  
  414.     detectDNSProxy : function()  // Returns true if the current URL is set to have its DNS lookup proxied via SOCKS
  415.     {
  416.         var uri = this.ios.newURI(flagState.url, null, null);
  417.         var proxyinfo = this.proxy.resolve(uri, 0);  // Finds proxy (shouldn't block thread; we already did this lookup to load the page)
  418.         return (proxyinfo != null) && (proxyinfo.flags & proxyinfo.TRANSPARENT_PROXY_RESOLVES_HOST);
  419.         // "network.proxy.socks_remote_dns" pref must be set to true for Firefox to set TRANSPARENT_PROXY_RESOLVES_HOST flag when applicable
  420.     },
  421.  
  422.     resolveHost : function()
  423.     {
  424.         this.request = this.dns.asyncResolve(flagState.host, 0, this, this.thread);
  425.     },
  426.  
  427.     onLookupComplete : function(nsrequest, nsrecord, status)
  428.     {
  429.         if (status == Components.results.NS_ERROR_ABORT)
  430.             return;  // ignore this.reset()
  431.  
  432.         this.request = null;
  433.         if (status != 0 || !nsrecord || !nsrecord.hasMore())
  434.         {
  435.             flagState.icon.src = "chrome://flagfox/content/icons/special/error.png";
  436.             flagState.icon.tooltipText = flagfoxstrings.getString("lookuperror");
  437.             var reason = (status==Components.results.NS_ERROR_UNKNOWN_HOST) ? ("Unknown host") : ("status="+status) ;
  438.             Components.utils.reportError("Flagfox error: DNS lookup fail: " + reason);
  439.             return;  // IP not found in DNS
  440.         }
  441.  
  442.         flagState.ip = nsrecord.getNextAddrAsString();
  443.         if (!flagState.IPisV6())
  444.         {
  445.             flagState.country = Flagfox_lookupIP(flagState.ip);
  446.             if (flagState.country == null)
  447.             {
  448.                 flagState.icon.tooltipText = flagState.serverString() + " - " + flagfoxstrings.getString("unknownsite");
  449.                 Components.utils.reportError("Flagfox warning: IP not in database");
  450.                 return;  // IP not in DB => Unknown site
  451.             }
  452.         }
  453.         else  // IPv6 address was returned
  454.         {
  455.             if (flagState.ip == "::1")  // Work around Vista stupidity
  456.             {
  457.                 flagState.country = ['-L',countrynames.getString('-L')];  // localhost
  458.             }
  459.             else
  460.             {
  461.                 flagState.icon.tooltipText = flagState.serverString() + " - " + flagfoxstrings.getString("unknownsite");
  462.                 Components.utils.reportError("Flagfox warning: IPv6 not supported");
  463.                 return;  // DB is IPv4 only => Unknown site
  464.             }
  465.         }
  466.  
  467.         // Set the image
  468.         Flagfox_setIconSrc();
  469.         // Set the tooltip
  470.         flagState.icon.tooltipText = flagState.tooltipString();
  471.  
  472.         // Explain things to user if this IP is not in the same country as the domain's registration (common user confusion)
  473.         Flagfox_checkTLD();
  474.     }
  475. };
  476.  
  477. function Flagfox_checkTLD()
  478. {
  479.     try
  480.     {
  481.         var tld = flagState.host.truncateAfterLastChar(".");
  482.         if (tld.length != 2)
  483.             return;
  484.         var code = tld.toUpperCase();  // TLD tweaked to search in list
  485.         switch (code)
  486.         {                                   // Special cases:
  487.             case "UK": code = "GB"; break;  // Different code for TLD vs in list
  488.             case "EU": return;              // Don't tell users European countries aren't in Europe
  489.             case "TV": return;              // Tuvalu sells its TLD use to media companies
  490.         }
  491.         var tldCountry = countrynames.getString(code);  // Throws an exception if not found
  492.         if (tldCountry.length && flagState.country[0] != code)
  493.         {
  494.             Flagfox_warning("flagfox.warn.tld", flagfoxstrings.getFormattedString("tldwarnmessage",[flagState.country[1],"."+tld,tldCountry]));
  495.         }
  496.     } catch (e) {}
  497. }
  498.  
  499. function Flagfox_warning(pref,message)  // Shows a slide-down info bar (max once per session for each unique message)
  500. {
  501.     if (!FFpreferences.getBoolPref(pref))
  502.         return;  // Disabled by user
  503.  
  504.     var messageID = Flagfox_hashString(message);
  505.     if (warningsThisSession.indexOf(messageID)!=-1)
  506.         return;  // Shown before
  507.     warningsThisSession.push(messageID);
  508.  
  509.     var notificationBox = window.getBrowser().getNotificationBox();
  510.     var priority = notificationBox.PRIORITY_WARNING_MEDIUM;
  511.     var buttons = [{ label: flagfoxstrings.getString("warnchecklabel"),
  512.                      callback: function() { FFpreferences.setBoolPref(pref,false); },  // Don't show this again
  513.                      accessKey: null, popup: null }];
  514.     notificationBox.appendNotification(message, pref, "chrome://flagfox/content/logo.png", priority, buttons);
  515. }
  516.  
  517. function Flagfox_cleanupPrefs()  // Wipes all Flagfox preferences that do not have defaults
  518. {
  519.     /* Both the user and default branches contain the exact same list of pref names,
  520.        even if any default values don't exist or any user values equal the default. */
  521.     var prefService = Components.classes["@mozilla.org/preferences-service;1"]
  522.                                 .getService(Components.interfaces.nsIPrefService);
  523.     var defaultBranch = prefService.getDefaultBranch("flagfox.");
  524.     var userBranch = prefService.getBranch("flagfox.");
  525.     var prefsList = userBranch.getChildList("",{});
  526.     if (!prefsList.length)
  527.         throw "Could not load Flagfox preferences list";
  528.     for (var i in prefsList)
  529.     {   // Exception means no default exists and this pref is not in use
  530.         try { Flagfox_getPref(defaultBranch,prefsList[i]); }
  531.         catch (e) { userBranch.clearUserPref(prefsList[i]); }
  532.     }
  533. }
  534.  
  535. function Flagfox_safeGetBoolPref(pref)
  536. {
  537.     try { return FFpreferences.getBoolPref(pref); }
  538.     catch (e) { return false; }
  539. }
  540.  
  541. String.prototype.cropTrailingChar = function(character)
  542. {
  543.     return (this.charAt(this.length-1)==character) ? this.slice(0,this.length-1) : this.valueOf();
  544. };
  545.  
  546. String.prototype.truncateAfterLastChar = function(character)
  547. {
  548.     return this.substring(this.lastIndexOf(character)+1);
  549. };
  550.